package com.hksj.ecm.service;

import cn.hutool.core.util.StrUtil;
import com.hksj.cbm.service.DeviceInstanceService;
import com.hksj.cbm.vo.SpaceModelVO;
import com.hksj.ecm.dto.EnergyFLowDTO;
import com.hksj.ecm.mapper.EnergyFLowMapper;
import com.hksj.ecm.vo.EnergyFLowChartVO;
import com.hksj.ecm.vo.EnergyFLowDeviceVO;
import com.hksj.tdengine.taos.service.TaosService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @author zengke
 * @version 1.0
 * @see EnergyFLowService
 * @since 2024/8/8 16:55
 */

@Service
public class EnergyFLowService {

    @Autowired
    private EnergyFLowMapper energyFLowMapper;

    @Autowired
    private EnergyTypeService energyTypeService;

    @Autowired
    private TaosService taosService;

    @Autowired
    private DeviceInstanceService deviceInstanceService;

    public List<EnergyFLowChartVO> queryEnergyFLowChartList(EnergyFLowDTO energyFLowDTO){

        //获取能耗类型code 水:ShuiB 电:DianB
//        String code = energyFLowDTO.getEnergyTypeCode();

        //根据能耗类型查询费率
//        EnergyTypeVO energyTypeVO = energyTypeService.queryEnergyRateByEnergyTypeCode(code);

        //根据能耗类型查询设备集合
        List<EnergyFLowDeviceVO> deviceList = energyFLowMapper.queryDeviceList(energyFLowDTO);

        //若设备列表为空直接返回
        if (ObjectUtils.isEmpty(deviceList)){
            return null;
        }

        //根据产品id分组
        Map<String, List<EnergyFLowDeviceVO>> productMap = deviceList.stream().collect(Collectors.groupingBy(EnergyFLowDeviceVO::getProductId));

        //遍历产品集合
        //设备能耗集合
        List<EnergyFLowDeviceVO> energyFLowDeviceList = new ArrayList<>();
        productMap.forEach((key,value) ->{

            //拼接超级表的名称
            String stableName = "properties".concat("_").concat(key);

            //判断超级表是否存在
            Boolean existStable = taosService.checkStable("jetlinks_clean_room", stableName);

            if (existStable){
                //存在超级表,查询设备能耗
                //获取当前产品下的所属设备及能耗
                /**
                 SELECT MIN(`numberValue`),MAX(`numberValue`),`deviceId`  as minValue
                 FROM jetlinks_clean_room.properties_1814100920127238144
                 where `deviceId` in ('1814104894448381952','yq002') and `property` = 'flow' and `_ts` <= '2024-08-02 09:49:14'
                 group by `deviceId`
                 */
                //设置要查询的设备列表
                energyFLowDTO.setEnergyFLowDeviceList(value);
                List<EnergyFLowDeviceVO> energyFLowDeviceVOS = energyFLowMapper.queryEnergyFlowDeviceList(stableName,energyFLowDTO);

                //添加设备能耗VO到energyFLowDeviceList
                energyFLowDeviceList.addAll(energyFLowDeviceVOS);
            }
        });

        //将设备能耗集合中的最小、最大累计值数据设置到设备集合中
        deviceList.forEach(device -> {
            energyFLowDeviceList.forEach(energyFLowDeviceVO -> {
                if (Objects.equals(device.getDeviceId(),energyFLowDeviceVO.getDeviceId())){
                    device.setMinValue(energyFLowDeviceVO.getMinValue());
                    device.setMaxValue(energyFLowDeviceVO.getMaxValue());

                    //能耗值 = 能耗累计最大值-能耗累计最小值
                    device.setEnergyValue(new BigDecimal(energyFLowDeviceVO.getMaxValue())
                            .subtract(new BigDecimal(energyFLowDeviceVO.getMinValue()))
                            .toString());
                }
            });
        });

        //将设备集合的数据组装成流向图
        //返回设备流向图
        return toEnergyFLowChartList(deviceList);
    }

    /**
     * 设置设备流向图
     * @param deviceList
     * @return
     */
    private List<EnergyFLowChartVO> toEnergyFLowChartList(List<EnergyFLowDeviceVO> deviceList) {

        //流向图列表
        List<EnergyFLowChartVO> energyFLowChartList = new ArrayList<>();

        //查询设备对应的建筑结构信息中文
        List<String> devicePathList = deviceList.stream().map(EnergyFLowDeviceVO::getBuildingPath).collect(Collectors.toList());
        Map<String, List<SpaceModelVO>> pathMap = deviceInstanceService.devicePathConvertToUTF8(devicePathList);

        /**
         * 路径:"园区,楼栋,楼层,房间"
         * 一个逗号代表设备挂载楼栋下
         * 两个逗号代表设备挂载楼层下
         * 三个逗号代表设备挂载房间下
         */
        List<EnergyFLowDeviceVO> deviceEnergyFlowList = deviceList.stream().peek(device -> {

            //获取设备的路径
            String buildingPath = device.getBuildingPath();

            //根据路径查询路径对应的中文
            List<SpaceModelVO> spaceModelVOS = pathMap.get(buildingPath);

            //空间建筑模型的集合不为空
            if (!ObjectUtils.isEmpty(spaceModelVOS)){
                //将除园区以外的建筑结构信息取出 并使用","拼接
                String buildingPathName = spaceModelVOS.stream().filter(spaceModel -> spaceModel.getLevel() > 0).map(SpaceModelVO::getModelName).collect(Collectors.joining(","));

                //将建筑结构信息中文设置到设备中
                device.setBuildingPathName(buildingPathName);
            }

        }).collect(Collectors.toList());

        //设备挂在楼栋下 level为1
        List<EnergyFLowDeviceVO> energyFLowDeviceOfBuildingVOS = deviceEnergyFlowList.stream().filter(deviceEnergyFlow -> Objects.equals(deviceEnergyFlow.getBuildingLevel(), "1")).collect(Collectors.toList());

        if (!ObjectUtils.isEmpty(energyFLowDeviceOfBuildingVOS)){

            //挂在楼栋下的设备不为空 pathName为 楼栋
            //根据“楼栋”进行分组 (并计算设备的能耗值)
            Map<String, List<EnergyFLowDeviceVO>> energyFLowDeviceMap = energyFLowDeviceOfBuildingVOS.stream().collect(Collectors.groupingBy(EnergyFLowDeviceVO::getBuildingPathName,Collectors.toList()));

            energyFLowDeviceMap.forEach((key,value) -> {

                //流向为 楼栋名称 -> 设备名称
                value.forEach(device ->{

                    //构建楼栋流向设备的能耗流向图VO
                    EnergyFLowChartVO energyFLowBuildingToDeviceChartVO = new EnergyFLowChartVO();

                    //设置流向的源、目标、值等信息
                    energyFLowBuildingToDeviceChartVO.setSource(key);
                    energyFLowBuildingToDeviceChartVO.setTarget(device.getDeviceName());
                    energyFLowBuildingToDeviceChartVO.setValue(device.getEnergyValue());

                    //将构建好的能耗流向图VO设置到list中
                    energyFLowChartList.add(energyFLowBuildingToDeviceChartVO);
                });
            });
        }

        //设备挂在楼层下 level为2
        List<EnergyFLowDeviceVO> energyFLowDeviceOfFloorVOS = deviceEnergyFlowList.stream().filter(deviceEnergyFlow -> Objects.equals(deviceEnergyFlow.getBuildingLevel(), "2")).collect(Collectors.toList());

        if (!ObjectUtils.isEmpty(energyFLowDeviceOfFloorVOS)){

            //挂在楼层下的设备不为空 pathName为 楼栋,楼层
            //以“楼栋,楼层”来分组
            Map<String, List<EnergyFLowDeviceVO>> energyFLowDeviceMap = energyFLowDeviceOfFloorVOS.stream().collect(Collectors
                    .groupingBy(EnergyFLowDeviceVO::getBuildingPathName, Collectors.toList()));//从后向前切割字符串 subAfter(字符串,分隔符,以字符串从前向后数是否是最后一个分隔符【例如此处为true则从后向前切割时以最后一个分隔符为基准从后往前切割的数组的第一个元素,此处为false则从后向前切割时以第一个分隔符为基准从后往前切割的数组的第一个元素】)

            //遍历能耗流向设备Map集合
            energyFLowDeviceMap.forEach((key,value) ->{

                //key:楼栋,楼层
                //value:设备
                value.forEach(device ->{

                    //构建 楼层流向设备的能耗流向图VO
                    EnergyFLowChartVO energyFLowFloorToDeviceChartVO = new EnergyFLowChartVO();

                    //设置流向的源、目标、值等信息
                    energyFLowFloorToDeviceChartVO.setSource(StrUtil.removeAll(key,","));//楼栋楼层去掉","
                    energyFLowFloorToDeviceChartVO.setTarget(device.getDeviceName());
                    energyFLowFloorToDeviceChartVO.setValue(device.getEnergyValue());

                    //构建楼栋流向楼层的能耗流向图VO
                    EnergyFLowChartVO energyFLowBuildingToFloorChartVO = new EnergyFLowChartVO();

                    //设置流向的源、目标、值等信息
                    energyFLowBuildingToFloorChartVO.setSource(StrUtil.subBefore(key,",",false));//取得楼栋
                    energyFLowBuildingToFloorChartVO.setTarget(StrUtil.removeAll(key,",")); //取得 "楼栋楼层"
                    energyFLowBuildingToFloorChartVO.setValue(device.getEnergyValue());

                    //将构建好的能耗流向图VO设置到list中
                    energyFLowChartList.add(energyFLowFloorToDeviceChartVO);
                    energyFLowChartList.add(energyFLowBuildingToFloorChartVO);
                });
            });
        }

        //设备挂载房间下 level为3
        List<EnergyFLowDeviceVO> energyFLowDeviceOfRoomVOS = deviceEnergyFlowList.stream().filter(deviceEnergyFlow -> Objects.equals(deviceEnergyFlow.getBuildingLevel(), "3")).collect(Collectors.toList());

        if (!ObjectUtils.isEmpty(energyFLowDeviceOfRoomVOS)){
            //挂在房间下的设备不为空 pathName为 园区,楼栋,楼层,房间
            //以 "楼栋,楼层,房间"来分组
            Map<String, List<EnergyFLowDeviceVO>> energyFLowDeviceMap = energyFLowDeviceOfRoomVOS.stream().collect(Collectors
                    .groupingBy(EnergyFLowDeviceVO::getBuildingPathName, Collectors.toList()));

            //遍历能耗流向设备Map集合
            energyFLowDeviceMap.forEach((key,value) -> {
                //key:楼栋,楼层,房间
                //value:设备
                value.forEach(device -> {
                    //构建 房间流向设备的能耗流向图VO
                    EnergyFLowChartVO energyFLowRoomToDeviceChartVO = new EnergyFLowChartVO();

                    //设置流向的源、目标、值等信息
                    energyFLowRoomToDeviceChartVO.setSource(StrUtil.removeAll(key,","));//楼栋楼层房间去掉","
                    energyFLowRoomToDeviceChartVO.setTarget(device.getDeviceName());
                    energyFLowRoomToDeviceChartVO.setValue(device.getEnergyValue());

                    //构建 楼层流向房间的能耗流向图VO
                    EnergyFLowChartVO energyFLowFloorToRoomChartVO = new EnergyFLowChartVO();

                    //设置流向的源、目标、值等信息
                    energyFLowFloorToRoomChartVO.setSource(StrUtil.removeAll(StrUtil.subBefore(key,",",true),","));//楼栋楼层
                    energyFLowFloorToRoomChartVO.setTarget(StrUtil.removeAll(key,","));//楼栋楼层房间
                    energyFLowFloorToRoomChartVO.setValue(device.getEnergyValue());

                    //构建 楼栋流向楼层的能耗流向图VO
                    EnergyFLowChartVO energyFLowBuildingToFloorChartVO = new EnergyFLowChartVO();

                    //设置流向的源、目标、值等信息
                    energyFLowBuildingToFloorChartVO.setSource(StrUtil.subBefore(key,",",false));//楼栋
                    energyFLowBuildingToFloorChartVO.setTarget(StrUtil.removeAll(StrUtil.subBefore(key,",",true),","));//楼栋楼层
                    energyFLowBuildingToFloorChartVO.setValue(device.getEnergyValue());

                    //将构建好的能耗流向图VO设置到list中
                    energyFLowChartList.add(energyFLowRoomToDeviceChartVO);
                    energyFLowChartList.add(energyFLowFloorToRoomChartVO);
                    energyFLowChartList.add(energyFLowBuildingToFloorChartVO);
                });
            });
        }

        //能耗流向图中可能存在相同的源和流向地址 即 source 和 target都相同的情况,需要将其合并
        return mergeEnergyFLowChart(energyFLowChartList);
    }

    private List<EnergyFLowChartVO> mergeEnergyFLowChart(List<EnergyFLowChartVO> energyFLowChartList) {

        //遍历energyFLowChartList 根据 "source,target"进行分组 然后将value对应的值求和
        Map<String, Double> energyFLowChartMap = energyFLowChartList.stream().collect(Collectors.groupingBy(energyFLowChartVO -> energyFLowChartVO.getSource().concat(",").concat(energyFLowChartVO.getTarget()), Collectors.summingDouble(energy -> Double.parseDouble(Objects.toString(energy.getValue(),"0")))));

        //energyFLowChartMap转换为list集合
        List<EnergyFLowChartVO> energyFLowChartVOS = energyFLowChartMap.entrySet().stream().map(entry -> {

            EnergyFLowChartVO energyFLowChartVO = new EnergyFLowChartVO();
            energyFLowChartVO.setSource(StrUtil.subBefore(entry.getKey(), ",", false));
            energyFLowChartVO.setTarget(StrUtil.subAfter(entry.getKey(), ",", false));
            energyFLowChartVO.setValue(String.valueOf(BigDecimal.valueOf(entry.getValue()).setScale(2, RoundingMode.HALF_UP)));

            return energyFLowChartVO;
        }).collect(Collectors.toList());

        return energyFLowChartVOS;
    }



}
